package middle.其他;

public class No1 {
    //              两整数之和
    //给你两个整数 a 和 b ，不使用 运算符 + 和 - ，计算并返回两整数之和。

    //只能解决a与b相同符号的情况，a、b异号的情况无法解决
    //原因：ab异号时无法得出正确的结果
    /*public int getSum(int a, int b) {
        int x,y,c = 0,res = 0,s,count = 1024,flag = 1;
        if (a < 0 && b < 0) {
            flag = -1;
            a = Math.abs(a);
            b = Math.abs(b);
        }

        while (count > 0) {
            x = a & 1;
            y = b & 1;
            if(((x & y & c) == 1) || (x ^ y ^ c) == 1){
                s = 1;
            }else{
                s = 0;
            }
            res = res | (s << 10);
            if ((x & y) == 1 || (x & c) == 1 || (y & c) == 1) {
                c = 1;
            }else{
                c = 0;
            }
            a = a >> 1;
            b = b >> 1;
            res = res >>> 1;
            count = count >> 1;
        }

        return res * flag;
    }*/
    //-------------------------------------------------------------------------------

    //-------------------------------------------------------------------------------
    //          手写版，将加法拆分成一位一位的来进行运算
    //成功版本：0ms
    /*public int getSum(int a, int b) {
        int x,y,c = 0,res = 0,s,count = -2147483648,flag = 1;
        if (a < 0 && b < 0) {
            flag = -1;
            a = Math.abs(a);
            b = Math.abs(b);
        }

        while (count != 0) {
            x = a & 1;
            y = b & 1;
            res = res >>> 1;

            //计算当前位的值
            if(((x & y & c) == 1) || (x ^ y ^ c) == 1){
                s = 1;
            }else{
                s = 0;
            }

            //相当于加上当前位
            res = res | (s << 31);

            //计算下一次计算时所需要的进位
            if ((x & y) == 1 || (x & c) == 1 || (y & c) == 1) {
                c = 1;
            }else{
                c = 0;
            }
            a = a >> 1;
            b = b >> 1;

            count = count >>> 1;
        }

        return res * flag;
    }*/
    //-----------------------------------------------------------------------

    //-----------------------------------------------------------------------
    //          精简版：将加法拆分成异或和&运算两部分
    //
    //思考的流程：
    // 数字在计算机内部以补码的形式存在——>分析补码的特性——>观察位运算所得到的结果是什么——>得到结果
    //
    //为什么要这样子拆分呢？当我们具体的分析一个例子的时候，可以发现，其二进制位在进行^运算时，得
    //到的结果就是不考虑进位时的本位和，而&运算得到的结果就是当前位是否产生进位，由于该进位要作用
    //于其前面的一位，所以我们将&运算之后的结果再左移一位再与本位和（即异或的结果）重复上述步骤，
    //最终进位会不断的往前推，当进位为零时，所得到的异或结果就是两数之和
    public int getSum(int a, int b){
        int temp;
        while (b != 0) {
            temp = (a & b) << 1;

            a = a ^ b;

            b = temp;
        }

        return a;
    }
}
